/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
//package MuleGame;
package MuleGUI;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import MuleBackend.AuctionPanel;
import MuleBackend.Board;
import MuleBackend.Client;
import MuleBackend.GameDriver;
import MuleBackend.InfoPanel;
import MuleBackend.Land;
import MuleBackend.Player;
import MuleBackend.Server;
import MuleBackend.StatusPanel;
import MuleBackend.StorePanel;
import MuleBackend.TownPanel;

/**
 * The BoardGUI class represents the board for the entire game
 * @author Jackson
 */
public class BoardGUI extends javax.swing.JFrame {
	ImageIcon image;
	//JFrame frame;
	JLabel[][] labels;
	JLabel[][] factory;
	JLabel[][] production;
	JLabel[][] crystite;
	JLabel[] priceLabel;
	JLabel randomLabel;
	ArrayList<InfoPanel> infoPanels;
	TownPanel townPanel;
	StorePanel storePanel;
	StatusPanel statusPanel;
	AuctionPanel auctionPanel;
	private HashMap<JLabel,Land> map;
	static JProgressBar timeBar;
	JMenuBar menuBar;
	JMenu newGameMenu;
    JMenu pauseMenu;
    JMenu joinMenu;
    JMenu exitMenu;
	JMenuItem newGameMenuStartItem;
	volatile Thread thread;
	int x,y,speed,muleX,muleY;
	ArrayList<Player> players;
	JPanel mainPanel;
	boolean startPlayer = false;
	int[] auctionX,auctionY;
	
	boolean boardPlayer = false, townPlayer = false, auctionLandPlayer = false, auctionGoodPlayer = false;
	
	private ImageIcon foodFactory = new ImageIcon("src/ShittyPackage/foodFactory.png");
	private ImageIcon energyFactory = new ImageIcon("src/ShittyPackage/energyFactory.png");
	private ImageIcon smithoreFactory = new ImageIcon("src/ShittyPackage/smithoreFactory.png");
	private ImageIcon crystiteFactory = new ImageIcon("src/ShittyPackage/crystiteFactory.png");
	private JMenuItem mntmHost;
	private JMenuItem mntmJoin;
	private JMenuItem mntmExit;
	
    /**
     * Creates new form Board
     */
    public BoardGUI() {
		labels = new JLabel[5][9];
		factory = new JLabel[5][9];
		production = new JLabel[5][9];
		priceLabel = new JLabel[4];
		crystite = new JLabel[5][9];
		infoPanels = new ArrayList<InfoPanel>();
		townPanel = new TownPanel();
		storePanel = null;
		statusPanel = new StatusPanel();
		auctionPanel = new AuctionPanel();
		auctionX = new int[4];
		auctionY = new int[4];
		x = 100;
		y = 100;
		speed = 10;
		muleX = x;
		muleY = y;
		
		buildGUI();
		map=new HashMap<JLabel,Land>();
    }	//end of constructor
    
    /**
     * this method create the main panel and
     * the menu of the board
     */
    private void buildGUI(){
    	setTitle("Mule Game (boardGUI)");
    	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	getContentPane().setPreferredSize(new Dimension(925, 600));
    	pack();
		setResizable(false);
    	setLocationRelativeTo(null);

		mainPanel = new JPanel();
		mainPanel.setBorder(new EmptyBorder(5,5,5,5));
		setContentPane(mainPanel);
		mainPanel.setLayout(null);
		
		menuBar = new JMenuBar();
    	
		newGameMenu = new JMenu("New Game");
        pauseMenu = new JMenu("Pause");
        joinMenu = new JMenu("Network");
        exitMenu = new JMenu("Exit");
        
        menuBar.add(newGameMenu);
        menuBar.add(pauseMenu);
        menuBar.add(joinMenu);
        
        mntmHost = new JMenuItem("Host");
        mntmHost.addActionListener(new HostButtonListener());
        
        joinMenu.add(mntmHost);
        
        mntmJoin = new JMenuItem("Join");
        joinMenu.add(mntmJoin);
        menuBar.add(exitMenu);
        
        mntmExit = new JMenuItem("Exit");
        exitMenu.add(mntmExit);
        
        randomLabel=new JLabel("");
        randomLabel.setBounds(0,475,900,25);
        randomLabel.setHorizontalTextPosition(JLabel.CENTER);
        randomLabel.setForeground(Color.WHITE);
        randomLabel.setVisible(false);
        getContentPane().add(randomLabel);
        
        newGameMenuStartItem = new JMenuItem("Start");
        newGameMenuStartItem.addActionListener(new StartButtonListener());
        
        newGameMenu.add(newGameMenuStartItem);
		setJMenuBar(menuBar);
		
		addKeyListener(new PlayerControl());
		setFocusable(true);
		setFocusTraversalKeysEnabled(false);
    }
    
    /**
     * private helper method to add the information panels of all the players to the board GUI 
     */
    public void addInfoPanels(){
   		for (int i=0; i<4 ;i++){
   			if (i<players.size()){
   				InfoPanel thepanel = new InfoPanel(players.get(i));
   				infoPanels.add(thepanel);
   				getContentPane().add(thepanel);
   				thepanel.setBounds(185*i,500,185,100);
   			}else{
   				InfoPanel thepanel = new InfoPanel(i+1);
   				infoPanels.add(thepanel);
   				getContentPane().add(thepanel);
   				thepanel.setBounds(185*i,500,185,100);
   			}
   		}
    	getContentPane().add(statusPanel);
    	statusPanel.setBounds(0,0,900,720);
    	statusPanel.setVisible(false);
    	addAuctionPanels();
   		storePanel = new StorePanel();
   		getContentPane().add(storePanel);
   		storePanel.setBounds(185*4,500,185,100);
    	getContentPane().add(townPanel);
    	townPanel.setBounds(0,0,900,720);
    	townPanel.setVisible(false);
    	getContentPane().add(statusPanel);
    	statusPanel.setBounds(0,0,900,720);
    	statusPanel.setVisible(false);
    	addAuctionPanels();
    }
    
    /**
     * add Auction panel to the board GUI
     */
    public void addAuctionPanels(){
		priceLabel[0] = new JLabel("Buy");
		priceLabel[0].setFont(new java.awt.Font("Tahoma", 0, 18));
		priceLabel[0].setBounds(200,400,50,20);
		priceLabel[1] = new JLabel("Buy");
		priceLabel[1].setFont(new java.awt.Font("Tahoma", 0, 18));
		priceLabel[1].setBounds(350,400,50,20);
		priceLabel[2] = new JLabel("Buy");
		priceLabel[2].setFont(new java.awt.Font("Tahoma", 0, 18));
		priceLabel[2].setBounds(500,400,50,20);
		priceLabel[3] = new JLabel("Buy");
		priceLabel[3].setFont(new java.awt.Font("Tahoma", 0, 18));
		priceLabel[3].setBounds(650,400,50,20);

		for (int i=0; i<priceLabel.length;i++){
			priceLabel[i].setVisible(false);
		}
		
		auctionPanel.setBounds(0,0,900,720);
		auctionPanel.setVisible(false);
		
		auctionX[0] = 200; auctionY[0] = 400;
		auctionX[1] = 350; auctionY[1] = 400;
		auctionX[2] = 500; auctionY[2] = 400;
		auctionX[3] = 650; auctionY[3] = 400;
		
		getContentPane().add(priceLabel[0]);
		getContentPane().add(priceLabel[1]);
		getContentPane().add(priceLabel[2]);
		getContentPane().add(priceLabel[3]);
    	getContentPane().add(auctionPanel);
    }
    
    /**
     * this method display Status GUI
     */
    public void addStatusPanel(){
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(false);
				factory[i][j].setVisible(false);
				crystite[i][j].setVisible(false);
			}
    	}
		getContentPane().setPreferredSize(new Dimension(925, 600));
		pack();
    	statusPanel.remove();
    	statusPanel.drawPlayer();
    	statusPanel.setVisible(true);
    }
    
    /**
     * this method remove Status GUI
     */
    public void removeStatusPanel(){
    	statusPanel.setVisible(false);
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(true);
				factory[i][j].setVisible(true);
				crystite[i][j].setVisible(true);
			}
    	}
    }
    
    public void addLandAuction(){
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(false);
				factory[i][j].setVisible(false);
				crystite[i][j].setVisible(false);
			}
    	}
    	for (int i=0; i<GameDriver.game.getPlayerList().size();i++){
    		priceLabel[i].setText("Buy");
    		priceLabel[i].setVisible(true);
		}
    	auctionPanel.setVisible(true);
    	auctionLandPlayer = true;
    	townPlayer = false;
    	boardPlayer = false;
    	auctionGoodPlayer = false;
    	startPlayer(x,y,10);
    }
    
    public void hideLandAuction(){
    	auctionX[0] = 200; auctionY[0] = 400;
		auctionX[1] = 350; auctionY[1] = 400;
		auctionX[2] = 500; auctionY[2] = 400;
		auctionX[3] = 650; auctionY[3] = 400;
    	for (int i=0; i<GameDriver.game.getPlayerList().size();i++){
    		
			priceLabel[i].setVisible(false);
		}
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(true);
				factory[i][j].setVisible(true);
				crystite[i][j].setVisible(true);
			}
    	}
    	auctionPanel.setVisible(false);
    	auctionLandPlayer = false;
    	stopPlayer();
    }
    
    public void startLandAuction(Land landForSale){
    	auctionPanel.startLandAuction(landForSale);
    	//auctionPanel.landAuction();
    }
    
    public void addGoodAuction(String str){
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(false);
				factory[i][j].setVisible(false);
				crystite[i][j].setVisible(false);
			}
    	}
    	for (int i=0; i<GameDriver.game.getPlayerList().size();i++){
			priceLabel[i].setVisible(true);
			priceLabel[i].setText("Buy");
		}
    	auctionPanel.goodAuction(str);
    	auctionPanel.setVisible(true);
    	auctionGoodPlayer = true;
    	auctionLandPlayer = false;
    	townPlayer = false;
    	boardPlayer = false;
    	startPlayer(x,y,10);
    }
    
    public void hideGoodAuction(){
    	auctionX[0] = 200; auctionY[0] = 400;
		auctionX[1] = 350; auctionY[1] = 400;
		auctionX[2] = 500; auctionY[2] = 400;
		auctionX[3] = 650; auctionY[3] = 400;
    	for (int i=0; i<GameDriver.game.getPlayerList().size();i++){
			priceLabel[i].setVisible(false);
		}
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(true);
				factory[i][j].setVisible(true);
				crystite[i][j].setVisible(true);
			}
    	}
    	auctionPanel.setVisible(false);
    	auctionGoodPlayer = false;
    }
    
    /**
     * this method display town
     */
    public void addTownPanel(int x, int y){
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(false);
				factory[i][j].setVisible(false);
				crystite[i][j].setVisible(false);
			}
    	}
    	townPanel.setPlayer(GameDriver.game.getActivePlayer());
    	townPlayer = true;
    	boardPlayer = false;
    	auctionGoodPlayer = false;
    	auctionLandPlayer = false;
    	townPanel.setVisible(true);
    	startPlayer(x,y,15);
    }
    
    /**
     * this method remove town display
     */
    public void removeTownPanel(){
    	townPanel.setVisible(false);
    	townPlayer = false;
    	boardPlayer = true;
    	auctionGoodPlayer = false;
    	auctionLandPlayer = false;
    	for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				labels[i][j].setVisible(true);
				factory[i][j].setVisible(true);
				crystite[i][j].setVisible(true);
			}
    	}
    }
    
    public void setMule(boolean boo){townPanel.setMule(boo);}
    
    public boolean playersValid(int players){
		if (players < 5 && players > 1)return false;
		return true;
	}
    
    /**
     * this method create progress bar inside board
     * this method is called from addMap method
     */
	public void addProgressBar(){
        timeBar = new javax.swing.JProgressBar();
        timeBar.setLocation(900, 0);
        timeBar.setSize(25, 500);
        timeBar.setStringPainted(true);
        timeBar.setOrientation(SwingConstants.VERTICAL);
        timeBar.setBackground(Color.BLACK);
        getContentPane().add(timeBar);
	}
    
    /**
     * creates a GUI representation of the MULE map
     */
    public void addMap(){
		players = GameDriver.game.getPlayerList();
		Land[][] landsArray = GameDriver.game.getLandsArray();
		
		for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				image = landsArray[i][j].getImage();
				labels[i][j] = new JLabel(image);
				factory[i][j] = new JLabel();
				production[i][j] = new JLabel();
				crystite[i][j] = new JLabel();
				labels[i][j].setBounds(100*j,100*i, 100, 100);
				factory[i][j].setBounds(100*j,100*i, 100, 100);
				crystite[i][j].setBounds(100*j,100*i, 100, 100);
				production[i][j].setBounds(100*j,(100*i)+70,30,30);
				getContentPane().add(crystite[i][j]);
				getContentPane().add(production[i][j]);
				getContentPane().add(factory[i][j]);
				getContentPane().add(labels[i][j]);
				map.put(labels[i][j], landsArray[i][j]);
			}
		}
		addProgressBar();
		addInfoPanels();
		addLandListener();
		hideProduction();
		getContentPane().setPreferredSize(new Dimension(925, 600));
		pack();
    }
    
    /**
     * show production GUI
     */
    public void showProduction(){
   		Land[][] lands = GameDriver.game.getLandsArray();
    	for (int i = 0; i < lands.length; i++){
    		for(int j = 0; j < lands[i].length; j++){
    			production[i][j].setVisible(true);
    			if (lands[i][j].getOwner()!=null){
    				production[i][j].setFont(new java.awt.Font("Tahoma", 0, 24));
    				production[i][j].setText(lands[i][j].produce()+"");
    				production[i][j].setForeground(Color.WHITE);
    			}else{
    				production[i][j].setText("");	
    			}
    		}
    	}
    }
    
    /**
     * remove production GUI
     */
    public void hideProduction(){
    	for (int i = 0; i < production.length; i++){
    		for(int j = 0; j < production[i].length; j++){
    			production[i][j].setText("");
    			production[i][j].setVisible(false);
			}
		}
    }
    
    /**
     * adds listeners to the board
     * execute this method before addTownListener.
     */
    public void addLandListener(){		
    	for (int i = 0; i < labels.length; i++){
    		for(int j = 0; j < labels[i].length; j++){
    				labels[i][j].addMouseListener(new AddLandListener());
			}
		}
    }
    
	/**
	 * getter method to get the progress bar
	 * @return the timebar
	 */
	public static JProgressBar getJProgressBar(){
		return timeBar;
	}
    
	/**
	 * updates all the information panels on the board
	 */
	public void updateInfoPanels(){
		for (int i=0; i<players.size(); i++){
			InfoPanel panel = infoPanels.get(i);
			panel.updatePanel();
		}
		storePanel.updatePanel();
	}    
    
    /**
     * this method set the start location for players
     * @param x the coordinate of x-axis
     * @param y the coordinate of y-axis
     */
    public void startPlayer(int x, int y,int speed){
    	this.x = x;
		this.y = y;
		muleX = x;
		muleY = y;
		this.speed = speed;
		setFocusable(true);
		startPlayer = true;
		repaint();
    }
    
    /**
     * this remove the player from 
     */
    public void stopPlayer(){
    	setFocusable(false);
    	startPlayer = false;
    	auctionGoodPlayer = false;
    	auctionLandPlayer = false;
    	townPlayer = false;
    	boardPlayer = false;
    	repaint();
    }
    
    /**
     * this method create the player character 
     */
    public void paint(Graphics g){
		super.paint(g);

		if (startPlayer){
			if (boardPlayer){
				ImageIcon character = GameDriver.game.getActivePlayer().getRace();
				g.drawImage(character.getImage(),x, y, 50, 50,null);
				if (GameDriver.game.getCurrentPlayer().getMuleImage()!=null)
					g.drawImage(GameDriver.game.getCurrentPlayer().getMuleImage().getImage(),muleX,muleY,50, 50,null);
			}
			if (townPlayer){
				int mule = GameDriver.game.getTown().getMuleStock();
				ImageIcon muleImage = new ImageIcon("src/ShittyPackage/player'sMule.png");
				if (GameDriver.game.getCurrentPlayer() != null){
					g.drawImage(GameDriver.game.getActivePlayer().getRace().getImage(), x, y,100, 100, null);
					if (GameDriver.game.getCurrentPlayer().getMuleImage() != null)
						g.drawImage(GameDriver.game.getActivePlayer().getMuleImage().getImage(),muleX,muleY,75, 75,null);
					for (int i=1; i<=mule; i++){
						if (i<=11){
							g.drawImage(muleImage.getImage(),885,510-(15*i),15, 20,null);
						}else if (i<=22){
							int j = i-12;
							g.drawImage(muleImage.getImage(),870,510-(15*j),15, 20,null);
						}else{
							int j = i-22;
							g.drawImage(muleImage.getImage(),855,510-(15*j),15, 20,null);
						}
					}
				}
			}
			if (auctionLandPlayer){
				int buybar = 450;
				g.setColor(Color.black);
				Graphics2D g2d = (Graphics2D) g;
				g2d.setStroke (new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[] {2f}, 0f) );
				ArrayList<Player> players = GameDriver.game.getPlayerList();
				for (int i=0; i<players.size();i++){
					int index = Player.returnIndexByID(players, i+1);
					g.drawImage(players.get(index).getRace().getImage(), auctionX[i], auctionY[i], 50, 50,null);
					if (buybar > auctionY[i]) buybar = auctionY[i];
					priceLabel[i].setBounds(auctionX[i],auctionY[i]+10,50,20);
				}
				g.drawLine(150, buybar, 750, buybar);
			}
			if (auctionGoodPlayer){
				int sellbar = 100, buybar = 440;
				g.setColor(Color.black);
				Graphics2D g2d = (Graphics2D) g;
				g2d.setStroke (new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[] {2f}, 0f) );
				ArrayList<Player> players = GameDriver.game.getPlayerList();
				for (int i=0; i<players.size();i++){
					int index = Player.returnIndexByID(players, i+1);
					if(auctionPanel.isBuyer(i+1)){
						g.drawImage(players.get(index).getRace().getImage(), auctionX[i], auctionY[i], 50, 50,null);
						if (buybar > auctionY[i]) buybar = auctionY[i];
						priceLabel[i].setBounds(auctionX[i],auctionY[i]+10,50,20);
					}
					else{
						g.drawImage(players.get(index).getRace().getImage(), auctionX[i], auctionY[i]-50, 50, 50,null);
						if (sellbar < auctionY[i]) sellbar = auctionY[i];
						priceLabel[i].setBounds(auctionX[i],auctionY[i]-40,50,20);
					}
				}
				g.drawLine(150, sellbar, 750, sellbar);
				g.drawLine(150, buybar, 750, buybar);
			}
			
		}
		
	}
    
    /*
     * Methods for Land Auction and Land Sale
     */
    
    /**
     * Picks a land for auction
     * @param board the game board
     * @return returns a random free piece of land
     */
    private Land pickLand(Board board){
    	ArrayList<Land> freeLands = board.getFreeLands();
    	if(freeLands.size()==0)
    		return null;
    	Random random = new Random();
    	int i = random.nextInt(freeLands.size());
    	return freeLands.get(i);
    }
    
    /**
     * gets the auction land and displays it
     * 
     * @return  free land in board, or null if there is no free piece of land
     */
    public Land startLandSale(){
    	Board board = GameDriver.game.getBoard();
    	Land freeLand = pickLand(board);
    	int index = board.findLandIndex(freeLand);
    	if(index==-1)
    		return null;
    	System.out.println("LAND SALE INDEX = " + index/9 + " " + index%9);
    	for(int k=0;k<3;k++){
    		//System.out.println("blink");
    		labels[index/9][index%9].setBorder(new LineBorder(Color.BLACK, 2));
    	}
    	//labels[index/9][index%9].setBorder(null);
    	return freeLand;
    }
    /**
     * colorLand colors a piece of land with the specified color
     * @param row row index of land
     * @param col column index of land
     * @param colorString color to be painted, null if you want color to be removed
     */
    public void colorLand(int row, int col, Color landColor){
    	if(landColor==null){
    		labels[row][col].setBorder(null);
    		return;
    	}
    	labels[row][col].setBorder(new LineBorder(landColor,2));
    }
    
    /**
     * uses the above colorLand to color a piece of land by taking in different parameters
     * @param land land to be colored
     * @param player the player who owns the land
     */
    
    public void colorLand(Land land, Player player){
    	int row = land.getRow()+1;
    	int col = land.getCol()+1;
    	System.out.println("Row = " + row + " Col = " + col);
    	Color color = null;
    	if(player==null)
    		color = null;
    	else
    		color = player.getColor();
    	colorLand(row,col,color);
    }
    
    /*
     * End of methods for land auction and land sale
     */
    
	/**
	 * These methods are for use primarily with the PubListener in StoreGUI.
	 * 
	 * The getTurnPercentRemaining() method accesses the progress bar on the right hand
	 * side of the board and returns the percentage of the bar remaining at the time of 
	 * the method's call.
	 * 
	 * The endTurn() method is called at the end of the PubListener as a terminating
	 *function for the current player's turn.
	 *
	 *@author Phil
	 *
	 */
    public double getTurnPercentRemaining()
	{
		return getJProgressBar().getPercentComplete();
	}

	/**
	 * getter method to get the board gui
	 */
	public BoardGUI getBoardGUI() {
		return this;
	}
	
	/**
	 * tells the player what random event happened
	 * @param the random event that happened
	 */
	public void showRandomLabel(String message){
		randomLabel.setText(message);
		randomLabel.setVisible(true);
	}
	
	/**
	 * hide the label for the random event message
	 */
	public void hideRandomLabel(){
		randomLabel.setVisible(false);
	}
	
	/**
	 * land listener class that determines what to do
	 * when a land is clicked
	 * @author Jackson
	 *
	 */
	public class AddLandListener extends MouseAdapter {
		
		boolean enabled;
	   	
		/**
		 * constructor for the addlandlistener class
		 */
	   	public AddLandListener() {
	   		enabled=true;
	   	}
	   	
	   	/**
	   	 * action event that happens when a land is clicked
	   	 */
	   	public void mouseClicked(MouseEvent event) {
	   		freeLandLogic(event);	//logic for assigning lands to players during land selection phase
	   	}
	   	
	   	/**
	   	 * private helper method that assigns free land
	   	 * @param e the mouse event of clicking a land
	   	 */
	   	private void freeLandLogic(MouseEvent e){
	   		if(!enabled)return;
	   		
	   		Land[][] lands = GameDriver.game.getLandsArray();
	   		int theRoundNumber = GameDriver.game.getRoundNumber();
	   		Player activePlayer = GameDriver.game.getActivePlayer();
	   		
	   		if (activePlayer != null && freeLandStage(activePlayer.getPlayerID())) {
	   			
	   	   		
			   		JLabel label = (JLabel)e.getSource();
					Color color = activePlayer.getColor();
		   		
		   		for (int row = 0; row < labels.length; row++) {
		   			for (int column = 0; column < labels[row].length; column++) {
		   				if (label == labels[row][column]) {
		   					if (notOwned(row, column)) {
		   						if (theRoundNumber < 3) {
			   						label.setBorder(new LineBorder(color, 2));
			   						activePlayer.addLand(lands[row][column]);
			   						GameDriver.game.setCurrentPlayer(null);
			   						GameDriver.game.endTimer();
		   						} else {
				   					if (activePlayer.getMoney() >= lands[row][column].getPrice()) {
			   							label.setBorder(new LineBorder(color, 2));
				   						activePlayer.addLand(lands[row][column]);
				   						activePlayer.deductMoney(lands[row][column].getPrice());
				   						GameDriver.game.setCurrentPlayer(null);
				   						GameDriver.game.endTimer();
				   					}
				   				}
		   					}	//end of if (not owned) statement
		   				}
		   			}
		   		}	//end of double for loop
	   		}	//end of if statement
	   	}	//end of freeLandLogic
	   	
	   	/**
	   	 * helper method to determine if it is
	   	 * the free land stage or not
	   	 * @param currentPlayerID current player
	   	 * @return true if it is the free land stage and there is a player
	   	 */
	   	private boolean freeLandStage(int currentPlayerID){
	   		if (currentPlayerID != 0 && GameDriver.game.getCurrentStage().equals("freeLand")){
	   			return true;
	   		}
	   		else {
	   			return false;
	   		}
	   	}
	   	
	   	/**
	   	 * helper method to determine if the land
	   	 * is owned or not
	   	 * @param row row of the land
	   	 * @param column column of the land
	   	 * @return
	   	 */
	   	private boolean notOwned(int row, int column){
	   		Player currentPlayer = GameDriver.game.getActivePlayer();
	   		Land[][] lands = GameDriver.game.getLandsArray();
	   		if (row == 2 && column == 4)
	   			return false;
	   		if (lands[row][column].getOwner() == null) {
	   			lands[row][column].setOwner(currentPlayer);
	   			return true;
	   		}
	   		return false;
	   	}
	} //end of LandListener class
	
	
	/**
	 * inner class for the start button listener
	 * that starts the game
	 * @author Jackson
	 *
	 */
	public class StartButtonListener implements ActionListener {
	    	
		/**
		 * constructor for the start button listener
		 */
	    public StartButtonListener() {
	    	//empty
	    }
	    
	    /**
	     * action event that happens when the start button i clicked
	     */
	    public void actionPerformed(ActionEvent e) {
	    	new StartGUI().setVisible(true);
	    	GameDriver.game.setGameType("local");
	    }
	} //end of StartButtonListener class


	public class HostButtonListener implements ActionListener {
    	
		/**
		 * constructor for the start button listener
		 */
	    public HostButtonListener() {
	    	//empty
	    }
	    
	    /**
	     * action event that happens when the host button is clicked
	     * 
	     */
	    public void actionPerformed(ActionEvent e) {
	    	try {
	    		if(GameDriver.game.server == null)
	    		{
	    			GameDriver.game.setGameType("network");
	    			GameDriver.game.server = new Server();
	    			NameGUI.numPlayer = Integer.parseInt(JOptionPane.showInputDialog("Choose number of players (2-4):"));
		    		while (playersValid(NameGUI.numPlayer))
		    		NameGUI.numPlayer = Integer.parseInt(JOptionPane.showInputDialog("Please enter between 2 and 4 players!","Choose number of players (2-4):"));
		    		new MultiplayerGUI().setVisible(true);
	    		}
	    		else
	    			JOptionPane.showMessageDialog(null,"There is already a host.");
	    		
			}catch (IOException e1) {

    			JOptionPane.showMessageDialog(null,"There is already a host.");
			}
	    }
	} //end of StartButtonListener class

	/**
	 * the class allow the player character to move using keyboard
	 * @author Spyro
	 *
	 */
	private class PlayerControl implements KeyListener{
		
		public void keyPressed(KeyEvent e){
			if (boardPlayer)boardActionPerformed(e);
			if (townPlayer)townActionPerformed(e);
			if (auctionLandPlayer){
				System.out.println("LISTENER ADDED!");
				GameDriver.game.getTimer().setDelay(1000);
				landAuctionActionPerformed(e);
			}
			if (auctionGoodPlayer){
				System.out.println("LISTENER ADDED!");
				goodAuctionActionPerformed(e);
			}
			
		}
		@Override
		public void keyTyped(KeyEvent e) {
			
		}
		@Override
		public void keyReleased(KeyEvent e) {
			if (auctionLandPlayer){
				GameDriver.game.getTimer().setDelay(100);
			}
		}
	}	//end of player contorll clss
	
	/**
	 * this is the helper method for board keyboard listener
	 * @param e key event
	 */
	public void boardActionPerformed(KeyEvent e){
		char ch = e.getKeyChar();
		
		if (ch == 'a' || e.getKeyCode() == KeyEvent.VK_LEFT)
			if (x>5){
				x = x - speed;
				muleX = x+50;
				muleY = y;
			}
		if (ch == 'w' || e.getKeyCode() == KeyEvent.VK_UP)
			if (y>40){
				y = y - speed;
				muleY = y+50;
				muleX = x;
			}
		if (ch == 'd' || e.getKeyCode() == KeyEvent.VK_RIGHT)
			if (x<850){
				x = x + speed;
				muleX = x-50;
				muleY = y;
			}
		if (ch == 's' || e.getKeyCode() == KeyEvent.VK_DOWN)
			if (y<490){
				y = y + speed;
				muleY = y-50;
				muleX = x;
			}
		if (ch == ' '){
			boardStuff();
		}
		if (x>=370 && x<=390 && y>=200 && y<=300){
			addTownPanel(10,245);
		}
		if (x>=460 && x<=480 && y>=200 && y<=300){
			addTownPanel(800,245);
		}
		if (x>=400 && x<=480 && y>=200 && y<=220){
			addTownPanel(405,50);
		}
		if (x>=400 && x<=480 && y>=300 && y<=320){
			addTownPanel(405,461);
		}
		repaint();
	}
	
	/**
	 * this is the helper method for town keyboard listener
	 * @param e key event
	 */
	public void townActionPerformed(KeyEvent e){
		char ch = e.getKeyChar();
		
		if (ch == 'a' || e.getKeyCode() == KeyEvent.VK_LEFT)
			if (x>=0 && townPanel.isValid(0,x,y)){
				x = x - speed;
				muleX = x+80;
				muleY = y;
				townPanel.moveToBoard(x,y);
			}
		if (ch == 'w' || e.getKeyCode() == KeyEvent.VK_UP)
			if (y>50 && townPanel.isValid(1,x,y)){
				y = y - speed;
				muleY = y+75;
				muleX = x;
				townPanel.moveToBoard(x,y);
			}
		if (ch == 'd' || e.getKeyCode() == KeyEvent.VK_RIGHT)
			if (x<810 && townPanel.isValid(2,x,y)){
				x = x + speed;
				muleX = x-75;
				muleY = y;
				townPanel.moveToBoard(x,y);
			}
		if (ch == 's' || e.getKeyCode() == KeyEvent.VK_DOWN)
			if (y<455 && townPanel.isValid(3,x,y)){
				y = y + speed;
				muleY = y-75;
				muleX = x;
				townPanel.moveToBoard(x,y);
			}
		System.out.println("x: "+x+", y: "+y);
		townPanel.doStuff(x,y);
		repaint();
	}
	
	public void landAuctionActionPerformed(KeyEvent e){
		char ch = e.getKeyChar();
		int playerSize = GameDriver.game.getPlayerList().size();
//		GameDriver.game.getTimer().setDelay(10000);
		if (playerSize>=1){
			if (ch == 'q' && auctionPanel.isPlayerLandValid(auctionY[0],1,0)){
				auctionY[0] = auctionY[0]-speed;
			}
			if (ch == 'a' && auctionPanel.isPlayerLandValid(auctionY[0],2,0)){
				auctionY[0] = auctionY[0]+speed;
			}
		}
		if (playerSize>=2){
			if (ch == 'e' && auctionPanel.isPlayerLandValid(auctionY[1],1,1)){
				auctionY[1] = auctionY[1]-speed;
			}
			if (ch == 'd' && auctionPanel.isPlayerLandValid(auctionY[1],2,1)){
				auctionY[1] = auctionY[1]+speed;
			}
		}
		if (playerSize>=3){
			if (ch == 't' && auctionPanel.isPlayerLandValid(auctionY[2],1,2)){
				auctionY[2] = auctionY[2]-speed;
			}
			if (ch == 'g' && auctionPanel.isPlayerLandValid(auctionY[2],2,2)){
				auctionY[2] = auctionY[2]+speed;
			}
		}
		if (playerSize>=4){
			if (ch == 'u' && auctionPanel.isPlayerLandValid(auctionY[3],1,3)){
				auctionY[3] = auctionY[3]-speed;
			}
			if (ch == 'j' && auctionPanel.isPlayerLandValid(auctionY[3],2,3)){
				auctionY[3] = auctionY[3]+speed;
			}
		}
		for (int i=0; i<playerSize;i++){
			if (auctionPanel.getBid(i) != 0){
				priceLabel[i].setText(""+auctionPanel.getBid(i));
			}else{
				priceLabel[i].setText("Buy");
			}
		}
//		GameDriver.game.getTimer().setDelay(100);
		repaint();
	}
	
	public void setAuctionWinner(){
		auctionPanel.setWinner();
	}
	
/**
 * Method that updates good auction phase and resets title
 * 
 */
	public void updateAuctionPhase(){
		auctionPanel.updatePhase();
	}
	
	public void goodAuctionActionPerformed(KeyEvent e){
		char ch = e.getKeyChar();
		int playerSize = GameDriver.game.getPlayerList().size();
		int auctionSpeed = auctionPanel.getSpeed();
//		GameDriver.game.getTimer().setDelay(10000);
		if (playerSize>=1){
			if (ch == 'q' && auctionPanel.isPlayerActionValid(true,1)){
				auctionY[0] = auctionY[0]-auctionSpeed;
			}
			if (ch == 'a' && auctionPanel.isPlayerActionValid(false,1)){
				auctionY[0] = auctionY[0]+auctionSpeed;
			}
		}
		if (playerSize>=2){
			if (ch == 'e' && auctionPanel.isPlayerActionValid(true,2)){
				auctionY[1] = auctionY[1]-auctionSpeed;
			}
			if (ch == 'd' && auctionPanel.isPlayerActionValid(false,2)){
				auctionY[1] = auctionY[1]+auctionSpeed;
			}
		}
		if (playerSize>=3){
			if (ch == 't' && auctionPanel.isPlayerActionValid(true,3)){
				auctionY[2] = auctionY[2]-auctionSpeed;
			}
			if (ch == 'g' && auctionPanel.isPlayerActionValid(false,3)){
				auctionY[2] = auctionY[2]+auctionSpeed;
			}
		}
		if (playerSize>=4){
			if (ch == 'u' && auctionPanel.isPlayerActionValid(true,4)){
				auctionY[3] = auctionY[3]-auctionSpeed;
			}
			if (ch == 'j' && auctionPanel.isPlayerActionValid(false,4)){
				auctionY[3] = auctionY[3]+auctionSpeed;
			}
		}
		if(ch=='b'){
			int[] res = auctionPanel.isPurchaseValid();
			updateInfoPanels();
			if(res[0] != -1){
				auctionY[res[0]] = 400;
			}
			if(res[1] != -1){
				auctionY[res[1]] = 120;
			}
		}
		if(ch=='s')
			auctionPanel.showPlayerLists();
		for (int i=0; i<playerSize;i++){
			if(auctionPanel.isBuyer(i+1)){
				if (auctionPanel.getGoodBid(i) != 0){
					priceLabel[i].setText(""+auctionPanel.getGoodBid(i));
				}else{
					priceLabel[i].setText("Buy");
				}
			}
			else
			if(auctionPanel.isSeller(i+1)){
				priceLabel[i].setText("" + auctionPanel.getGoodSellPrice(i));
			}
			else{
				priceLabel[i].setText("Done");
			}
				
		}
//		GameDriver.game.getTimer().setDelay(100);
		repaint();
	}
	
	/**
	 * this method performed tasks when the space is pressed
	 */
	public void boardStuff(){
		Player currentPlayer = GameDriver.game.getCurrentPlayer();
//		ArrayList<Player> players = GameDriver.game.getPlayerList();
		Land[][] landsArray = GameDriver.game.getLandsArray();
		for (int j=1; j<=5; j++){
			if (y>=(100*(j-1)) && y<=(100*j)){
				for (int i=1; i<=9; i++){
					if (x>=(100*(i-1)) && x<=(100*i)){
						System.out.println(j+","+i);
						Player currentPlay = landsArray[j-1][i-1].getOwner();
						if (currentPlayer.getMule()==6){
							ImageIcon images = landsArray[j-1][i-1].getCrystiteImage();
							crystite[j-1][i-1].setIcon(images);
							currentPlayer.setMule(0);
						}
						if (currentPlayer.getMule()==7 && currentPlay == (currentPlayer)){
							currentPlayer.removeLand(landsArray[j-1][i-1]);
							landsArray[j-1][i-1].setOwner(null);
							labels[j-1][i-1].setBorder(null);
							factory[j-1][i-1].setIcon(null);
							currentPlayer.addMoney(100);
							currentPlayer.setMule(0);
						}
						if (currentPlayer.getMule()<=5 && currentPlay == (currentPlayer)){
							ImageIcon images = createFactory(currentPlayer.getMule());
							landsArray[j-1][i-1].setFactory(currentPlayer.getMule()-1);
							if (images != null){
								factory[j-1][i-1].setIcon(images);
							}
						}
						currentPlayer.setMule(0);
					}
				}
				GameDriver.game.updateInfoPanels();
			}
		}
		
	}
	
	/**
	 * this is the helper method for creating factory
	 * @param mule
	 * @return
	 */
	private ImageIcon createFactory(int mule){
		if (mule == 2)return foodFactory;
		if (mule == 3)return energyFactory;
		if (mule == 4)return smithoreFactory;
		if (mule == 5)return crystiteFactory;
		return null;
	}
} //end of BoardGUI class